package com.google.code.retrobox.editor.maps;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.google.code.retrobox.editor.dataCollections.MapData;

public class MapIO {

	public void exporMapToHeader(File file, MapEditor mapEditor)
			throws Exception {

		String path = file.getAbsolutePath();
		if (!path.endsWith(".h")) {
			path = path + ".h";
		}

		BufferedWriter out = new BufferedWriter(new FileWriter(path));
		out.write("// Auto generated map header file by ALFA software \n\n" +

		"// Map properties: \n" +

		"// Width: " + mapEditor.map.getMapWidth() + "\n" + "// Height: "
				+ mapEditor.map.getMapHeight() + "\n\n" +

				"#define MAP1 { \\\n");

		int i = 1;
		for (char element : mapEditor.map.getDataRaw()) {
			out.write(String.format("0x%X, ", (int) element));
			if (i == 12) {
				out.write("\\\n");
				i = 0;
			}
			i++;
		}

		out.write("}");
		out.close();
	}

	public void saveMap(File file, MapEditor mapEditor) throws Exception {
		String path = file.getAbsolutePath();
		if (!path.endsWith(".xml")) {
			path = path + ".xml";
			file = new File(path);
		}

		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document doc = db.newDocument();

		Element root = doc.createElement("tileMap");
		root.setAttribute("version", "1.0");
		doc.appendChild(root);

		Element tileData = doc.createElement("mapData");
		tileData.setAttribute("width", String.valueOf(mapEditor.map
				.getMapWidth()));
		tileData.setAttribute("height", String.valueOf(mapEditor.map
				.getMapHeight()));

		StringBuilder data = new StringBuilder();
		int i = 1;
		for (char element : mapEditor.map.getDataRaw()) {
			data.append(String.format("0x%X, ", (int) element));
			if (i == 12) {
				data.append("\\\n");
				i = 0;
			}
			i++;
		}

		tileData.appendChild(doc.createTextNode(data.toString()));
		root.appendChild(tileData);

		// write the content into xml file
		TransformerFactory transformerFactory = TransformerFactory
				.newInstance();
		Transformer transformer = transformerFactory.newTransformer();
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		DOMSource source = new DOMSource(doc);
		StreamResult result = new StreamResult(file);
		transformer.transform(source, result);
	}

	public MapData importMapFromHeader(File file, MapEditor mapEditor) throws Exception {

		String path = file.getAbsolutePath();
		if (!path.endsWith(".h")) {
			path = path + ".h";
		}
		int w = 0;
		int h = 0;
		List<Character> data = new ArrayList<Character>();

		FileInputStream fstream = new FileInputStream(file);
		DataInputStream in = new DataInputStream(fstream);
		BufferedReader br = new BufferedReader(new InputStreamReader(in));

		String line;
		while ((line = br.readLine()) != null) {
			Scanner sc = new Scanner(line);

			while (sc.hasNext() && w == 0) {
				if (sc.next().indexOf("Width:") >= 0) {
					try {
						w = sc.nextInt();
					} catch (Exception exc) {
						throw new Exception("Error parsing width from file!!!",
								exc);
					}
					break;
				}
			}

			while (sc.hasNext() && h == 0) {
				if (sc.next().indexOf("Height:") >= 0) {
					try {
						h = sc.nextInt();
					} catch (Exception exc) {
						throw new Exception(
								"Error parsing height from file!!!", exc);
					}
					break;
				}
			}

			if (w != 0 && h != 0) {
				while ((line = br.readLine()) != null) {
					if (line.indexOf("#define") >= 0) {
						while ((line = br.readLine()) != null) {
							sc = new Scanner(line);

							while (sc.hasNext()) {
								String next;
								if ((next = sc.next()).toLowerCase()
										.startsWith("0x")) {
									int lastIndex = next.length();
									int tmp = next.lastIndexOf(",");
									if (tmp > -1) {
										lastIndex = tmp;
									}
									try {
										data.add((char) (Integer.parseInt(next
												.substring(2, lastIndex), 16)));
									} catch (Exception e) {
										throw new Exception(
												"Error parsing hex from text file",
												e);
									}
								}
							}
						}

						break;
					}
				}
				break;
			}
		}
		in.close();

		char[] dataArray = new char[data.size()];

		for (int i = 0; i < data.size(); i++) {
			dataArray[i] = data.get(i);
		}

		MapData md = new MapData(mapEditor.tileset, dataArray, w, h);
		return md;
	}

	public MapData loadMap(File file, MapEditor mapEditor) throws Exception {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document doc = db.parse(file);
		doc.getDocumentElement().normalize();
		System.out.println("Root element "
				+ doc.getDocumentElement().getNodeName());
		if (!doc.getDocumentElement().getNodeName().equals("tileMap")) {
			throw new Exception("Unknown file format, illegal tag: "
					+ doc.getDocumentElement().getNodeName());
		}
		if (!doc.getDocumentElement().getAttribute("version").equals("1.0")) {
			throw new Exception("Unsupported file version "
					+ doc.getDocumentElement().getAttribute("version"));
		}

		NodeList list = doc.getElementsByTagName("mapData");
		List<Character> data = new ArrayList<Character>();
		if (list.getLength() == 1) {
			String tileData = list.item(0).getTextContent();
			//System.out.println(tileData);
			int height = 0;
			int width = 0;

			if ((((Element)list.item(0)).getAttribute("height") == "")) {
				throw new Exception("Missing height attribute."
						+ doc.getDocumentElement().getAttribute("height"));
			} else {
				height = Integer.parseInt(((Element)list.item(0)).getAttribute("height"));
			}
			if ((((Element)list.item(0)).getAttribute("width") == "")) {
				throw new Exception("Missing height attribute."
						+ ((Element)list.item(0)).getAttribute("width"));
			} else {
				width = Integer.parseInt(((Element)list.item(0)).getAttribute("width"));
			}			
			if (width != 0 && height != 0) {

				Scanner sc = new Scanner(tileData);

				while (sc.hasNext()) {
					String next;
					if ((next = sc.next()).toLowerCase().startsWith("0x")) {
						int lastIndex = next.length();
						int tmp = next.lastIndexOf(",");
						if (tmp > -1) {
							lastIndex = tmp;
						}
						try {
							data.add((char) (Integer.parseInt(next.substring(2,
									lastIndex), 16)));
						} catch (Exception e) {
							throw new Exception(
									"Error parsing hex from text file", e);
						}
					}
				}
			}
			char[] dataArray = new char[data.size()];

			for (int i = 0; i < data.size(); i++) {
				dataArray[i] = data.get(i);
			}

			MapData md = new MapData(mapEditor.tileset, dataArray, width, height);
			return md;
		} else {
			throw new Exception("Illegal format in data structure.");
		}
		
	}
}
